

import 'dart:async';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:logger/logger.dart';
import 'package:xim/common/cache_management.dart';
import 'package:xim/common/util/datetime.dart';
import 'package:xim/http/http.dart';
import 'package:path/path.dart';

/// TODO ffmpeg: https://juejin.cn/post/7240750927052161079
/// 文件资源API
class GfsApi {

  static final  log = Logger();

  /// return 图片名称
  static Future<String> upload(File file,{bool usingOriginalName=false}) async {
    Future<FormData> formData() async {
      return FormData.fromMap({
        'date': DateTime.now().toIso8601String(),
        'usingOriginalName': usingOriginalName,
        'file': await MultipartFile.fromFile(file.path,filename: basename(file.path)),
      });
    }
    var resp = await dio.post("/gfs/upload", data: await formData());
    return resp.data['data'];
  }

  /// 文件上传
  static Future<String> uploadBytes(List<int> bytes, String fileName, {bool usingOriginalName=false}) async {
    Future<FormData> formData() async {
      return FormData.fromMap({
        'date': DateTime.now().toIso8601String(),
        'usingOriginalName': usingOriginalName,
        'file': MultipartFile.fromBytes(bytes, filename: fileName),
      });
    }
    log.i("upload file $fileName at ${DateTime.now().format("yyyy-MM-dd HH:mm:ss")}");
    var resp = await dio.post("/gfs/upload", data: await formData());
    log.i("upload file $fileName success at ${DateTime.now().format("yyyy-MM-dd HH:mm:ss")}");
    return resp.data['data'];
  }

  /// 分片
  static List<List<int>> slice(List<int> fileData, {int chunkSize=10*1024*1024}){
    var fileSize = fileData.length;
    var i = 0;
    List<List<int>> fileSlices = [];
    for(i=chunkSize;i<fileSize;i+=chunkSize){
      fileSlices.add(fileData.sublist(i-chunkSize, i));
    }
    if(i>fileSize){
      fileSlices.add(fileData.sublist(i-chunkSize, fileSize));
    }
    return fileSlices;
  }

  /// 获取分片上传token
  static Future<String> requestChunkToken(String fileName) async {
    var resp = await dio.postResult("/gfs/chunk/upload/token", queryParameters: {"fileName": fileName});
    return resp.data;
  }

  /// 分片上传
  static Future<String> sliceBytesUpload(List<List<int>> fileSlices, String fileName) async {
    var chunkUploadToken = await requestChunkToken(fileName);
    log.i("获取 chunkUploadToken 成功：$chunkUploadToken");
    // upload
    var files = List.generate(fileSlices.length, (index) => "$fileName-$index");
    List<Future<Response<dynamic>>> resp = [];
    for(var j=0;j<fileSlices.length;j++){
      var res = uploadChunk(chunkUploadToken, j+1,fileName, fileSlices[j], chunkName: files[j]);
      resp.add(res);
    }
    await Future.wait(resp);
    // merge
    return (await mergeChunkFiles(fileName, chunkFiles: files)).data['data'];
  }

  /// 文件分片上传
  static Future<void> sliceUpload(File file, {int chunkSize=5*1024}) async {
    var list = file.readAsBytesSync().toList();
    List<List<int>> fileSlices = slice(list);
    // upload
    sliceBytesUpload(fileSlices, basename(file.path));
  }

  /// 上传分片
  static Future<Response<dynamic>> uploadChunk(
      String chunkToken, int index, String fileName,List<int> data, {String? chunkName}) async {
    Future<FormData> formData() async {
      return FormData.fromMap({
        'date': DateTime.now().toIso8601String(),
        'index': index,
        'chunkName': chunkName,
        'chunkToken': chunkToken,
        'fileName': fileName,
        'file': MultipartFile.fromBytes(data, filename: fileName),
      });
    }
    log.i("upload file $chunkName at ${DateTime.now().format("yyyy-MM-dd HH:mm:ss")}");
    var resp = await dio.post("/gfs/chunk/upload", data: await formData());
    log.i("upload file $chunkName success at ${DateTime.now().format("yyyy-MM-dd HH:mm:ss")}");
    return resp;
  }

  /// 分片合并
  static Future<ResponseResult> mergeChunkFiles(String fileName, {List<String>? chunkFiles}){
    return dio.postResult("/gfs/chunk/merge", queryParameters: {"fileName":fileName, "chunkFiles": chunkFiles});
  }

  /// 图片预览
  static String getGfsFileDownloadPath(String gfsFileName){
    return "${dio.options.baseUrl}/gfs/preview/$gfsFileName";
  }

  /// 下载图片
  static Future<File> downloadGfsFile(String gfsFileName, {bool usingCache=true}) async {
    var downloadPath = getGfsFileDownloadPath(gfsFileName, );
    if(usingCache){
      return FileCacheManager.instance.getSingleFile(downloadPath);
    }
    return FileCacheManager
        .instance
        .downloadFile(downloadPath, force: true)
        .then((value) => value.file);
  }


  /// 视频分片

}